package cn.yaboya.basic.service.Impl;

import cn.yaboya.basic.constant.BaseConstants;
import cn.yaboya.basic.exception.BusinessException;
import cn.yaboya.basic.service.IVerifyCodeService;
import cn.yaboya.basic.utils.StrUtils;
import cn.yaboya.basic.utils.VerifyCodeUtils;
import cn.yaboya.user.domain.User;
import cn.yaboya.user.service.IUserService;
import cn.yaboya.basic.vo.RegisterVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class IVerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IUserService userService;

    @Override
    public String graph(String key) {
        // 1.根据传过来的uuid 判定是否为空 如果为空就是恶意攻击
        if (StringUtils.isEmpty(key)) {
            throw new BusinessException("请传递参数");
        }
        // 2.得到一个随机的4位数
        String code = StrUtils.getComplexRandomString(4);
        // 3.将uuid值和一个随机的4位数 放入到redis缓存中
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
        // 4.将code值重新编码码为base64 字符串
        String base64 = VerifyCodeUtils.VerifyCode(100, 35, code);

        return base64;
    }

    @Override
    public void smsCode(RegisterVo vo) {
        final String phone = vo.getPhone();
        String type = vo.getType();

        // 1.判断参数是否为空
        if (StringUtils.isEmpty(phone)) {
            throw new BusinessException("参数错误请重新输入");
        }

        String smsCodeKey = null;
        // 判断是要做注册业务
        if (("register").equals(type)) {
            // 如果type等于register，说明是注册账号发送短信验证码，那么先把注册账号私有业务逻辑做了
            // 1.判断图形验证码
            isImageCode(vo);
            // 2.使用业务键拼接手机号从Redis中获取手机验证码 register:phone
            smsCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_REGISTER_PREFIX + phone;

        } else if (("binder").equals(type)) {
            // 如果type等于binder那么就直接发送短信验证码
            // 1.使用业务键拼接手机号从Redis中获取手机验证码 binder:phone
            smsCodeKey = BaseConstants.VerifyCodeConstant.BUSINESS_BINDER_KEY + phone;

        }


        // 拼接手机验证码业务键值
        final Object smsCodeValueTmp = redisTemplate.opsForValue().get(smsCodeKey);
        // 4.2 判断验证码是否为空 或者已过期 为空则生成新的验证码
        String smsCode = "";
        // 4.2.1如果验证码 为空 则代表用户第一次获取 直接生成四位随机码即可
        // 不为空 则第一步判断时间是否超过一分钟 超过才能重新获取 小于则提示用户
        // 超过一分钟 重新获取 我们使用之前的随机码即可
        if (smsCodeValueTmp == null) {
            smsCode = StrUtils.getComplexRandomString(4);
        } else {
            // 4.2.2 截取业务键值 的值 取到电话号码
            String[] smsCodeValueArray = smsCodeValueTmp.toString().split(":");
            // 4.2.3 获取老的时间戳
            Long oldTime = Long.valueOf(smsCodeValueArray[1]);
            // 4.2.4 获取现在的时间戳
            Long nowTime = System.currentTimeMillis();
            // 判断时间是否超过一分钟
            if (nowTime - oldTime <= 1*60*1000) {
                throw new BusinessException("请一分钟重试");
            }
            // 判断是否超过一分钟
            smsCode = smsCodeValueArray[0];
        }
        // 6.设置时间为三分钟 到redis
        String smsCodeValue = smsCode + ":" + System.currentTimeMillis();
        redisTemplate.opsForValue().set(smsCodeKey, smsCodeValue, 3, TimeUnit.MINUTES);
        // 7.发送验证码
//        SmsUtils.sendMsg(phone, "你的验证码是"+ smsCode);

        System.out.println("你的验证码是"+ smsCode);


    }

    private void isImageCode(RegisterVo vo) {

        // 1.判断手机号和图形验证码是否为空
        String imageCodeKey = vo.getImageCodeKey();
        String imageCodeValue = vo.getImageCodeValue();
        String phone = vo.getPhone();

        if(StringUtils.isEmpty(imageCodeKey)
                || StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数错误，请输入正确参数!");
        }

        // 2判断手机号是否被注册，如果被注册提示用户
        // 2.1.根据电话查询用户
        User user = userService.loadByPhone(phone);
        // 2.2.如果用户信息不为空，说明此电话已注册用户，那么提示用户登录即可
        if(user != null){
            throw new BusinessException("账号已注册，请直接登录!");
        }

        // 3.校验图形验证码在Redis中是否存在以及是否正确
        // 3.1.根据图形验证码Key值从Redis中获取图形验证码code
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
        // 3.2.判断Redis中是否存有该Key的图形验证码，如果没有，说明用户非正常手段访问，那么抛出异常
        if(imageCodeTmp == null){
            throw new BusinessException("验证码为空，请输入验证码!");
        }
        // 3.3.获取到了图形验证码，需要判断前端传递的验证码与Redis中存入的是否一致，如果不一致提示用户
        if(!imageCodeTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请输入正确验证码!");
        }
    }


}

